#include <glf.h>
#include <glfwindow.h>
#include <glftime.h>
#include <glfu.h>

//GL program handle
static GLuint programHandle = 0;

//Vertex attribute location
static GLint vertexLocation = -1;

static GLint modelviewLocation = -1;
static GLint projectionLocation = -1;

//Draw program attributes
static const int programAttributes[]=
{ 
	GL_VERTEX_SHADER, (int)"modelview_projection.vert", 
	GL_FRAGMENT_SHADER, (int)"draw.frag", 
	0 
};

glfuShape_t shape = {0};

static void initialise(void* userdata)
{
	programHandle = glfuLoadProgram( programAttributes );
	if( programHandle != 0 )
	{
		glUseProgram( programHandle );
		vertexLocation = glGetAttribLocation( programHandle, "vertex" );
		if( vertexLocation != -1 )
		{
			glEnableVertexAttribArray( vertexLocation );
			glfuGenerateShape( &shape, GLFU_CUBE, GL_TRUE );
			glVertexAttribPointer( vertexLocation, shape.vertexTypeSize, shape.vertexType, GL_FALSE, 0, shape.vertices );
		}
		modelviewLocation = glGetUniformLocation( programHandle, "modelview" );
		projectionLocation = glGetUniformLocation( programHandle, "projection" );
	}
}

static void terminate(void* userdata)
{
	glfuDeleteShape( &shape );
	if( vertexLocation != -1 )
	{
		glVertexAttribPointer( vertexLocation, 0, 0, 0, 0, 0 );
		glDisableVertexAttribArray( vertexLocation );
		vertexLocation =-1;
	}
	if( programHandle != 0 )
	{
		glUseProgram( 0 );
		glfuUnloadProgram( programHandle );
		programHandle = 0;
	}
}

static void think(void* userdata)
{
}

static void render(void* userdata)
{
	float v[3];
	float m[16];
	float n[16];

	static float a = 0;

	a+=glfTimeDelta()*M_PI/3.0f;

	//Clear framebuffer
	glClear(GL_COLOR_BUFFER_BIT);

//ORTHOGRAPHIC
	
	//Set projection matrix
	//glfuOrthographicMatrix2d( m, -1, 1, -1, 1 );
	//glUniformMatrix4fv( projectionLocation, 1, GL_FALSE, m );
	
	//Set model view matrix
	//glfuIdentityMatrix( m );
	//glUniformMatrix4fv( modelviewLocation, 1, GL_FALSE, m );

//PERSPECTIVE

	glfuPerspectiveMatrix( m, M_PI/4, 640.0f / 480.0f, 0.1, 1000 );
	glUniformMatrix4fv( projectionLocation, 1, GL_FALSE, m );

	glfuLookAtMatrix( m, 0, 0, 200, 0, 0, 0, 0, 1, 0 );
	glfuRotationMatrixZ( n, a );
	glfuMultiplyMatrix( m, n );
	glfuRotationMatrixY( n, a );
	glfuMultiplyMatrix( m, n );
	glfuRotationMatrixX( n, a );
	glfuMultiplyMatrix( m, n );
	glUniformMatrix4fv( modelviewLocation, 1, GL_FALSE, m );

	//Draw


	//draw shape that has no index buffer
	//glDrawArrays( shape.primitiveType, 0, shape.numVertices );

	//draw shape that has index buffer
	glDrawElements( shape.primitiveType, shape.numIndices, shape.indexType, shape.indices );


}

static void resize(void* userdata)
{
	glViewport(0,0,glfGetWidth(),glfGetHeight());
}

int main(void)
{

	glfConfigSetAttribute(glfMajorVersion, 3);
	glfConfigSetAttribute(glfMinorVersion, 1);
	glfConfigSetAttribute(glfContextFlags, glfContextForwardCompatible);

	if( !glfCreateWindow( "Modelview projection", 640, 480 ) )
	{
		return -1;
	}
	
	glfSetCallBack(glfCallbackInitialise, initialise, NULL );
	glfSetCallBack(glfCallbackThink, think, NULL );
	glfSetCallBack(glfCallbackRender, render, NULL );
	glfSetCallBack(glfCallbackResize, resize, NULL );
	glfSetCallBack(glfCallbackTerminate, terminate, NULL );

	if( !glfMainloop() )
	{
		return -1;
	}

	glfDestroyWindow();

	return 0;
}
